/**
 ******************************************************************************
 * @file           : bsp_dma.c
 * @brief          : DMA Driver Implementation (STM32F1xx)
 ******************************************************************************
 * @attention
 *
 * DMA驱动程序实现文件
 * 提供DMA配置和管理功能
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/DMA/bsp_dma.h"
#include "./BSP/DMA/bsp_dma_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DMA_HandleTypeDef sg_dma_handle[7];  /*!< DMA句柄数组（DMA1_Channel1~7） */

/* Private function prototypes -----------------------------------------------*/
static void dma_clock_enable(DMA_Channel_TypeDef *channel);
static uint8_t dma_get_channel_index(DMA_Channel_TypeDef *channel);
static uint32_t dma_direction_to_hal(DMA_Direction_e direction);
static uint32_t dma_data_width_to_hal(DMA_DataWidth_e width);
static uint32_t dma_mode_to_hal(DMA_Mode_e mode);
static uint32_t dma_priority_to_hal(DMA_Priority_e priority);

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       初始化DMA
 *
 * @param[in]   config: DMA配置结构体指针
 *
 * @retval      DMA_Error_e: 错误码
 */
DMA_Error_e dma_init(const DMA_Config_t *config)
{
    uint8_t channel_index;
    
    /* 参数检查 */
    if (config == NULL || config->channel == NULL)
    {
        log_e("DMA配置参数错误");
        return DMA_ERROR_PARAM;
    }
    
    /* 使能DMA时钟 */
    dma_clock_enable(config->channel);
    
    /* 获取通道索引 */
    channel_index = dma_get_channel_index(config->channel);
    if (channel_index == 0xFF)
    {
        log_e("无效的DMA通道");
        return DMA_ERROR_PARAM;
    }
    
    /* 配置DMA */
    sg_dma_handle[channel_index].Instance = config->channel;
    sg_dma_handle[channel_index].Init.Direction = dma_direction_to_hal(config->direction);
    sg_dma_handle[channel_index].Init.PeriphInc = config->periph_inc ? DMA_PINC_ENABLE : DMA_PINC_DISABLE;
    sg_dma_handle[channel_index].Init.MemInc = config->memory_inc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE;
    sg_dma_handle[channel_index].Init.PeriphDataAlignment = dma_data_width_to_hal(config->periph_width);
    sg_dma_handle[channel_index].Init.MemDataAlignment = dma_data_width_to_hal(config->memory_width);
    sg_dma_handle[channel_index].Init.Mode = dma_mode_to_hal(config->mode);
    sg_dma_handle[channel_index].Init.Priority = dma_priority_to_hal(config->priority);
    
    if (HAL_DMA_Init(&sg_dma_handle[channel_index]) != HAL_OK)
    {
        log_e("DMA初始化失败");
        return DMA_ERROR_PARAM;
    }
    
    log_i("DMA初始化完成 Channel=0x%08X", (uint32_t)config->channel);
    return DMA_OK;
}

/**
 * @brief       反初始化DMA
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      DMA_Error_e: 错误码
 */
DMA_Error_e dma_deinit(DMA_Channel_TypeDef *channel)
{
    uint8_t channel_index = dma_get_channel_index(channel);
    
    if (channel_index == 0xFF)
    {
        return DMA_ERROR_PARAM;
    }
    
    HAL_DMA_DeInit(&sg_dma_handle[channel_index]);
    log_i("DMA反初始化完成");
    
    return DMA_OK;
}

/**
 * @brief       启动DMA传输
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      DMA_Error_e: 错误码
 */
DMA_Error_e dma_start(DMA_Channel_TypeDef *channel)
{
    uint8_t channel_index = dma_get_channel_index(channel);
    
    if (channel_index == 0xFF)
    {
        return DMA_ERROR_PARAM;
    }
    
    if (HAL_DMA_Start(&sg_dma_handle[channel_index], 0, 0, 0) != HAL_OK)
    {
        log_e("DMA启动失败");
        return DMA_ERROR_TRANSFER;
    }
    
    return DMA_OK;
}

/**
 * @brief       停止DMA传输
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      DMA_Error_e: 错误码
 */
DMA_Error_e dma_stop(DMA_Channel_TypeDef *channel)
{
    uint8_t channel_index = dma_get_channel_index(channel);
    
    if (channel_index == 0xFF)
    {
        return DMA_ERROR_PARAM;
    }
    
    HAL_DMA_Abort(&sg_dma_handle[channel_index]);
    log_d("DMA传输已停止");
    
    return DMA_OK;
}

/**
 * @brief       执行DMA传输
 *
 * @param[in]   channel: DMA通道
 * @param[in]   src_addr: 源地址
 * @param[in]   dst_addr: 目标地址
 * @param[in]   data_num: 数据数量
 *
 * @retval      DMA_Error_e: 错误码
 */
DMA_Error_e dma_transfer(DMA_Channel_TypeDef *channel, uint32_t src_addr, uint32_t dst_addr, uint32_t data_num)
{
    uint8_t channel_index = dma_get_channel_index(channel);
    
    if (channel_index == 0xFF)
    {
        return DMA_ERROR_PARAM;
    }
    
    if (HAL_DMA_Start(&sg_dma_handle[channel_index], src_addr, dst_addr, data_num) != HAL_OK)
    {
        log_e("DMA传输失败");
        return DMA_ERROR_TRANSFER;
    }
    
    log_d("DMA传输中... 数量=%u", data_num);
    return DMA_OK;
}

/**
 * @brief       检查DMA是否忙
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      uint8_t: 1=忙, 0=空闲
 */
uint8_t dma_is_busy(DMA_Channel_TypeDef *channel)
{
    return (channel->CCR & DMA_CCR_EN) ? 1 : 0;
}

/**
 * @brief       获取DMA剩余传输数量
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      uint32_t: 剩余数量
 */
uint32_t dma_get_counter(DMA_Channel_TypeDef *channel)
{
    return channel->CNDTR;
}

/**
 * @brief       DMA传输完成回调（弱函数）
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      无
 *
 * @note        用户可重写此函数
 */
__weak void dma_transfer_complete_callback(DMA_Channel_TypeDef *channel)
{
    /* 用户代码 */
    log_d("DMA传输完成 Channel=0x%08X", (uint32_t)channel);
}

/**
 * @brief       DMA传输错误回调（弱函数）
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      无
 *
 * @note        用户可重写此函数
 */
__weak void dma_transfer_error_callback(DMA_Channel_TypeDef *channel)
{
    /* 用户代码 */
    log_e("DMA传输错误 Channel=0x%08X", (uint32_t)channel);
}

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       使能DMA时钟
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      无
 */
static void dma_clock_enable(DMA_Channel_TypeDef *channel)
{
    if ((uint32_t)channel >= (uint32_t)DMA1_Channel1 && (uint32_t)channel <= (uint32_t)DMA1_Channel7)
    {
        __HAL_RCC_DMA1_CLK_ENABLE();
    }
#ifdef DMA2
    else if ((uint32_t)channel >= (uint32_t)DMA2_Channel1 && (uint32_t)channel <= (uint32_t)DMA2_Channel5)
    {
        __HAL_RCC_DMA2_CLK_ENABLE();
    }
#endif
}

/**
 * @brief       获取DMA通道索引
 *
 * @param[in]   channel: DMA通道
 *
 * @retval      uint8_t: 通道索引（0~6），0xFF表示无效
 */
static uint8_t dma_get_channel_index(DMA_Channel_TypeDef *channel)
{
    if (channel == DMA1_Channel1) return 0;
    if (channel == DMA1_Channel2) return 1;
    if (channel == DMA1_Channel3) return 2;
    if (channel == DMA1_Channel4) return 3;
    if (channel == DMA1_Channel5) return 4;
    if (channel == DMA1_Channel6) return 5;
    if (channel == DMA1_Channel7) return 6;
    
    return 0xFF;
}

/**
 * @brief       DMA方向转换为HAL库定义
 */
static uint32_t dma_direction_to_hal(DMA_Direction_e direction)
{
    switch (direction)
    {
        case DMA_DIR_PERIPH_TO_MEMORY:
            return DMA_PERIPH_TO_MEMORY;
        case DMA_DIR_MEMORY_TO_PERIPH:
            return DMA_MEMORY_TO_PERIPH;
        case DMA_DIR_MEMORY_TO_MEMORY:
            return DMA_MEMORY_TO_MEMORY;
        default:
            return DMA_PERIPH_TO_MEMORY;
    }
}

/**
 * @brief       数据宽度转换为HAL库定义
 */
static uint32_t dma_data_width_to_hal(DMA_DataWidth_e width)
{
    switch (width)
    {
        case DMA_DATA_WIDTH_BYTE:
            return DMA_PDATAALIGN_BYTE;
        case DMA_DATA_WIDTH_HALFWORD:
            return DMA_PDATAALIGN_HALFWORD;
        case DMA_DATA_WIDTH_WORD:
            return DMA_PDATAALIGN_WORD;
        default:
            return DMA_PDATAALIGN_BYTE;
    }
}

/**
 * @brief       DMA模式转换为HAL库定义
 */
static uint32_t dma_mode_to_hal(DMA_Mode_e mode)
{
    return (mode == DMA_MODE_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL;
}

/**
 * @brief       优先级转换为HAL库定义
 */
static uint32_t dma_priority_to_hal(DMA_Priority_e priority)
{
    switch (priority)
    {
        case DMA_PRIORITY_LOW:
            return DMA_PRIORITY_LOW;
        case DMA_PRIORITY_MEDIUM:
            return DMA_PRIORITY_MEDIUM;
        case DMA_PRIORITY_HIGH:
            return DMA_PRIORITY_HIGH;
        case DMA_PRIORITY_VERY_HIGH:
            return DMA_PRIORITY_VERY_HIGH;
        default:
            return DMA_PRIORITY_LOW;
    }
}
